#include <iostream>
#include <unistd.h>
#include <string>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>

#define NUM 1024
//创建管道，并实现父进程读取，子进程写入
using namespace std;

//该函数是让子进程对管道文件进行写入,一次写入一个s
void Write(int pfd[])
{
    string s = "this is test";
    char buffer[NUM];
    pid_t self = getpid();
    int number = 0;
    while(true)
    {
        sleep(1);
        buffer[0] = 0;//字符串清空,提醒程序员这只是一个缓冲区

        //将%s-%d-%d给了buffer,第二个参数是确定第一个参数的大小
        snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number++);

        //写入文件时,只要写入内容本身即可,后面的'/0'不考虑
        write(pfd[1], &buffer, strlen(buffer));
    }
    
}

void Read(int pfd[])
{
    char buffer[NUM];
    while(true)
    {
        sleep(5);
        buffer[0] = 0;//表示缓冲区为空

        //这里用sizeof是计算buffer的总大小,因为要将文件的内容存储进来
        //极端情况下是将整个buffer填满,因此采用sizeof的方式
        ssize_t n = read(pfd[0], buffer, sizeof(buffer));//第三个参数表示读取的大小
        //n返回读取到的数量(0表示文件末尾)

        if(n == 0)//read读到文件末尾了,已经读取结束
        {
            cout << "父进程已读取完毕" << endl;
            break;
        }

        else if(n > 0)
        {
            buffer[n] = 0;//假设读到5个内容(5字节),那么下标只会到4,那么用下标5将末尾置'/0'或0
            cout << "父进程接收:" << buffer << endl;
        }
    }
}


int main()
{
    int pfd[2] = {0};//0下标：读取 ； 1下标：写入
    int n = pipe(pfd);
    if(n<0)
        return 1;//用1表示管道（内存级文件）创建失败
    pid_t id = fork();
    if(id<0)
        return 2;//用2表示子进程创建失败
    
    if(id>0)//子进程
    {
        close(pfd[0]);//关闭子进程的读取
        Write(pfd);//实现对管道文件写入的函数
    }

    //父进程
    close(pfd[1]);//关闭父进程的写入
    Read(pfd);//实现对管道文件读取的函数

    waitpid(id,0,0);//进程等待

    return 0;//用0返回正常结束
}